home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / tracker-4.13.lha / tracker / Amiga / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-14  |  15.7 KB  |  639 lines

  1. /* amiga/ui.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: ui.c,v 1.22 1995/02/14 16:51:22 espie Exp espie $
  6.  * $Log: ui.c,v $
  7.  * Revision 1.22  1995/02/14  16:51:22  espie
  8.  * *** empty log message ***
  9.  *
  10.  * Revision 1.21  1995/02/13  22:05:42  espie
  11.  * Changed version number.
  12.  *
  13.  * Revision 1.20  1995/01/13  13:31:35  espie
  14.  * *** empty log message ***
  15.  *
  16.  * Revision 1.20  1994/06/22  21:54:12  Espie
  17.  * Split across other files.
  18.  * File requester !
  19.  * Added pause gadget.
  20.  * Uncentralized event handling using event management functions.
  21.  * Changed name to ui_win, added Show gadget.
  22.  * better coding for gadgets.
  23.  * Nasty bug with info: did not close the file properly.
  24.  * Fully working asynchronous interface.
  25.  * User feedback.
  26.  * Added missing autoinit
  27.  * Removed some typecasts.
  28.  * info facility.
  29.  * scroll post-synchronized output.
  30.  * notice.
  31.  * Cursor handling.
  32.  * Used of discard_buffer for premature ending.
  33.  * Mostly working.
  34.  * Just dies with a guru.
  35.  * Plus timing problems at start.
  36.  */
  37.  
  38. #include <proto/intuition.h>
  39. #include <proto/gadtools.h>
  40. #include <proto/exec.h>
  41. #include <dos/dos.h>
  42. #include <intuition/intuitionbase.h>
  43.  
  44. #include "defs.h"
  45. #include "version.h"
  46. #include "extern.h"
  47. #include "amiga/amiga.h"
  48. #include "tags.h"
  49. #include "prefs.h"
  50.  
  51. ID("$Id: ui.c,v 1.22 1995/02/14 16:51:22 espie Exp espie $")
  52.  
  53. XT unsigned int inhibit_output;
  54.  
  55. LOCAL void init_ui(void);
  56. LOCAL void do_set_current(VALUE current);
  57. LOCAL void handle_ui_window(GENERIC nothing);
  58.  
  59. LOCAL void (*INIT)(void) = init_ui;
  60.  
  61.  
  62. /* These two variables memorize where we actually are in
  63.  * the current song
  64.  */
  65. LOCAL int current_pattern;
  66.  
  67. #define SMALL_DELAY 3         /* in seconds */
  68.  
  69. /* And these when stuff last changed */
  70. LOCAL ULONG pattern_change_seconds, pattern_change_micros,
  71. song_change_seconds, song_change_micros;
  72.  
  73.  
  74. /* The basic user interface (a simple window) */
  75.  
  76. struct IntuitionBase *IntuitionBase = 0;
  77. struct GfxBase *GfxBase = 0;
  78. LOCAL struct Library *GadtoolsBase = 0;
  79. LOCAL struct Window *ui_win;
  80.  
  81. void set_busy_pointer(BOOL maybe)
  82.    {
  83.    if (IntuitionBase->LibNode.lib_Version < 39)
  84.       return;
  85.    if (ui_win)
  86.       SetWindowPointer(ui_win, WA_BusyPointer, maybe, WA_PointerDelay, TRUE, TAG_DONE, 0);
  87.    }
  88.  
  89. /* for asynchronous easy requests */
  90. LOCAL struct Window *notice_win = 0;
  91.  
  92.    /* for computing length */
  93. LOCAL struct IntuiText it;
  94.  
  95. #define SHIFT 4
  96. #define SPACEX 10
  97. #define SPACEY 4
  98.  
  99. #define WINDOW_TITLE "Experiment IV "        /* the space in case the font is italic */
  100.  
  101. LOCAL struct NewGadget template =
  102.    {
  103.    0, 0,
  104.    0, 0,
  105.    NULL,
  106.    0,
  107.    0,       /* gadget ID */
  108.    0,
  109.    NULL,
  110.    NULL
  111.    };
  112.  
  113. LOCAL struct NewMenu menu_template[] =
  114.    {
  115.    {NM_TITLE,  "Project",        0, 0, 0, 0},
  116.       {NM_ITEM,   "Load song...",   0, 0, 0, (void *)4},
  117.       {NM_ITEM,   "About...",       0, 0, 0, (void *)1},
  118.       {NM_ITEM,   "Quit",           0, 0, 0, (void *)2},
  119.    {NM_TITLE,  "Settings",       0, 0, 0, 0},
  120.          /* WARNING: check item_number if you add menu entries */
  121.       {NM_ITEM,   "PAL",            0, CHECKIT, 6, (void *)50},
  122.       {NM_ITEM,   "NTSC",           0, CHECKIT, 5, (void *)60},
  123.       {NM_ITEM,   "Custom",         0, CHECKIT, 3, (void *)3},
  124.    {NM_END,    0,                0, 0, 0, 0}
  125.    };
  126.  
  127. LOCAL struct Menu *menu = 0;
  128.  
  129. LOCAL APTR vi;
  130. LOCAL struct Screen *pub = 0;
  131. LOCAL struct Gadget *glist, *title_gad, *pattern_gad, *total_gad;
  132.  
  133. /* we precisely have seven gadgets */
  134. #define MAX_GADGET 6
  135.  
  136. /* all labelled with strings */
  137. LOCAL char *label[MAX_GADGET + 1] =
  138.    {
  139.    "|<",
  140.    "<<",
  141.    "//",
  142.    ">>", 
  143.    ">|",
  144.    "?",
  145.    "000",
  146.    };
  147.  
  148. #define G_NEXT 4
  149. #define G_RESTART_PREVIOUS 0
  150. #define G_REWIND 1
  151. #define G_FF 3
  152. #define G_SHOW 5
  153. #define G_PAUSE 2
  154. LOCAL struct ext_message *restart_msg = NULL;
  155.  
  156. LOCAL void cleanup_ui()
  157.    {
  158.    if (restart_msg)
  159.       {
  160.       send(restart_msg, TYPE_UNPAUSE);
  161.       restart_msg = 0;
  162.       }
  163.    if (ui_win)
  164.       {
  165.       remove_signal_handler(ui_win->UserPort->mp_SigBit);
  166.       SetWindowTitles(ui_win, 0, 0);
  167.       ClearMenuStrip(ui_win);
  168.       CloseWindow(ui_win);
  169.       ui_win = 0;
  170.       }
  171.    if (menu)
  172.       FreeMenus(menu);
  173.    if (glist)
  174.       FreeGadgets(glist);
  175.    if (vi)
  176.       FreeVisualInfo(vi);
  177.    if (pub)
  178.       UnlockPubScreen(NULL, pub);
  179.    while (notice_win)
  180.       await_events();
  181.    if (GfxBase)
  182.       CloseLibrary(GfxBase);
  183.    if (IntuitionBase)
  184.       CloseLibrary(IntuitionBase);
  185.    if (GadtoolsBase)
  186.       CloseLibrary(GadtoolsBase);
  187.    }
  188.    
  189.  
  190. LOCAL void init_ui(void)
  191.    {
  192.    struct Gadget *gad;
  193.    int i;
  194.    int max_width;
  195.    int width, height;
  196.    UWORD zoom[4];
  197.  
  198.    at_end(cleanup_ui);
  199.    IntuitionBase = OpenLibrary("intuition.library", 37);
  200.    if (!IntuitionBase)
  201.       end_all("No Intuition");
  202.    GadtoolsBase = OpenLibrary("gadtools.library", 37);
  203.    if (!GadtoolsBase)
  204.       end_all("No gadtools");
  205.    GfxBase = OpenLibrary("graphics.library", 37);
  206.    if (!GfxBase)
  207.       end_all("No graphics");
  208.    pub = LockPubScreen(NULL);
  209.    if (!pub)
  210.       end_all("No pubscreen");
  211.    vi = GetVisualInfo(pub, TAG_END);
  212.    if (!vi)
  213.       end_all("No VI");
  214.       {
  215.       int item_number;
  216.  
  217.       switch(get_pref_scalar(PREF_SPEED))
  218.          {
  219.       case 50:
  220.          item_number = 5; break;
  221.       case 60:
  222.          item_number = 6; break;
  223.       default:
  224.          item_number = 7; break;
  225.          }
  226.       menu_template[item_number].nm_Flags |= CHECKED;
  227.       }
  228.    menu = CreateMenus(menu_template, GTMN_FrontPen, BARDETAILPEN, TAG_END);
  229.    if (!menu)
  230.       end_all("No menus");
  231.    if (!LayoutMenus(menu, vi, TAG_END))
  232.       end_all("Menus badly formed");
  233.       
  234.       /* now to create the gadgets */
  235.       /* Compute max width/height according to the font */
  236.    it.ITextFont = pub->Font;
  237.    template.ng_TextAttr = pub->Font;
  238.    
  239.    max_width = 0;
  240.    for (i = 0; i < MAX_GADGET + 1; i++)
  241.       {
  242.       it.IText = label[i];  
  243.       width = IntuiTextLength(&it);
  244.       if (width > max_width)
  245.          max_width = width;
  246.       }
  247.     
  248.    max_width += SPACEX;
  249.    template.ng_Width = max_width;     
  250.    template.ng_Height = pub->Font->ta_YSize + SPACEY;
  251.  
  252.       /* set up Top/Left Edge of initial gadget according to Wbar */
  253.    template.ng_TopEdge = pub->WBorTop + 1 + 2 * template.ng_Height + SHIFT;
  254.    template.ng_LeftEdge = pub->WBorLeft + SHIFT; 
  255.  
  256.    gad = CreateContext(&glist);
  257.    if (!gad)
  258.       end_all("No context");
  259.    template.ng_VisualInfo = vi;
  260.       /* lay out gadgets */
  261.    for (i = 0; i < MAX_GADGET; i++)
  262.       {
  263.       template.ng_GadgetText = label[i];
  264.       gad = CreateGadget(BUTTON_KIND, gad, &template, TAG_END);
  265.       if (!gad)
  266.          end_all("Bad gadget");
  267.       template.ng_LeftEdge += template.ng_Width + SHIFT;
  268.       template.ng_GadgetID++;
  269.       }
  270.    width = template.ng_LeftEdge + pub->WBorRight;
  271.    height = template.ng_TopEdge + template.ng_Height + pub->WBorBottom + SHIFT;
  272.  
  273.       /* zoom box */
  274.    zoom[0] = ~0;
  275.    zoom[1] = ~0;
  276.    zoom[2] = width;
  277.    zoom[3] = pub->WBorTop + 1 + pub->Font->ta_YSize;
  278.  
  279.       /* title gadget */     
  280.    template.ng_GadgetText = "";
  281.    template.ng_Width = width - SHIFT - pub->WBorLeft - pub->WBorRight;
  282.    template.ng_Width -= 2 * max_width;
  283.    template.ng_TopEdge = pub->WBorTop + 1 + template.ng_Height + SHIFT;
  284.    template.ng_LeftEdge = SHIFT + pub->WBorLeft;
  285.    title_gad = gad = CreateGadget(TEXT_KIND, gad, &template, TAG_END);
  286.    if (!gad)
  287.       end_all("Bad gadget");
  288.       
  289.       /* pattern gadget */
  290.    template.ng_LeftEdge += template.ng_Width + SHIFT;
  291.    template.ng_Width = max_width;
  292.    pattern_gad = gad = CreateGadget(NUMBER_KIND, gad, &template, TAG_END);
  293.    if (!gad)
  294.       end_all("Bad gadget");
  295.  
  296.       /* total pattern */
  297.    template.ng_GadgetText = "/";
  298.    template.ng_LeftEdge += template.ng_Width + SHIFT;
  299.    total_gad = gad = CreateGadget(NUMBER_KIND, gad, &template, TAG_END);
  300.    if (!gad)
  301.       end_all("Bad gadget");
  302.    ui_win = OpenWindowTags(NULL, 
  303.       WA_Title, WINDOW_TITLE,
  304.       WA_Width, width,
  305.       WA_Height, height,
  306.       WA_MinWidth, zoom[2],
  307.       WA_MaxWidth, width,
  308.       WA_MinHeight, zoom[3],
  309.       WA_MaxHeight, height,
  310.       WA_AutoAdjust, TRUE,
  311.       WA_MouseQueue, 35,   /* we can't always answer messages */
  312.       WA_DepthGadget, TRUE,
  313.       WA_CloseGadget, TRUE,
  314.       WA_DragBar, TRUE,
  315.       WA_Zoom, zoom,
  316.       WA_Gadgets, glist,
  317.       WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | TEXTIDCMP | 
  318.                 IDCMP_REFRESHWINDOW | IDCMP_MENUPICK,
  319.       WA_NewLookMenus, TRUE,
  320.       WA_PubScreen, pub,
  321.       TAG_DONE, 0);
  322.    if (!ui_win)
  323.       end_all("No window");
  324.    GT_RefreshWindow(ui_win, NULL);  
  325.    SetMenuStrip(ui_win, menu);
  326.  
  327.    install_signal_handler(ui_win->UserPort->mp_SigBit, handle_ui_window, 0);
  328.    
  329.    /* build up scroll buffer stuff */
  330.    }
  331.  
  332. struct Screen *obtain_pubscreen(void)
  333.    {
  334.    INIT_ONCE;
  335.    
  336.    return pub;
  337.    }
  338.  
  339. /* Max number of input messages we can remember */
  340. #define MAX_INPUT 20
  341. LOCAL struct tag result[MAX_INPUT +1];
  342. LOCAL int i = 0;
  343.  
  344. LOCAL void handle_ui_window(GENERIC nothing)
  345.    {
  346.    struct IntuiMessage *msg;
  347.    UWORD number;
  348.    struct MenuItem *item;
  349.    int id;
  350.    VALUE temp;
  351.    
  352.    while((msg = GT_GetIMsg(ui_win->UserPort)) && i < MAX_INPUT)
  353.       switch(msg->Class)
  354.          {
  355.       case IDCMP_CLOSEWINDOW:
  356.          GT_ReplyIMsg(msg);
  357.          set_break();
  358.          break;
  359.       case IDCMP_MENUPICK:
  360.          number = msg->Code;
  361.          while (number != MENUNULL)
  362.             {
  363.             item = ItemAddress(menu, msg->Code);
  364.             switch((int)GTMENUITEM_USERDATA(item))
  365.                {
  366.             case 1:
  367.                notice(
  368. "Tracker "VERSION"\n\
  369.       by Marc Espie (Marc.Espie@ens.fr)\n\n\
  370. This is a giftware program\n\
  371. If you want, you can send me some money\n\
  372. My address is:\n\
  373.       Espie Marc\n\
  374.       60 rue du 4 septembre\n\
  375.       87100 Limoges\n\
  376.       France\n\n\
  377. For the most recent version:\n\
  378.       ftp Aminet or nic.funet.fi");
  379.                break;
  380.             case 2:
  381.                item = 0;
  382.                set_break();
  383.                break;
  384.             case 4:
  385.                launch_requester();
  386.                break;
  387.             case 50:
  388.             case 60:
  389.                result[i].type = UI_SET_BPM;
  390.                result[i++].data.scalar = (int)GTMENUITEM_USERDATA(item);
  391.                set_pref_scalar(PREF_SPEED, (int)GTMENUITEM_USERDATA(item));
  392.                break;
  393.             default:
  394.                break;
  395.                }
  396.             number = item->NextSelect;
  397.             }
  398.          GT_ReplyIMsg(msg);
  399.          break;
  400.       case IDCMP_REFRESHWINDOW:
  401.          GT_ReplyIMsg(msg);
  402.          GT_BeginRefresh(ui_win);
  403.          GT_EndRefresh(ui_win, TRUE);
  404.          break;
  405.       case IDCMP_GADGETUP:
  406.          id = ((struct Gadget *)msg->IAddress)->GadgetID;
  407.          switch(id)
  408.             {
  409.          case G_NEXT:
  410.             result[i++].type = UI_NEXT_SONG;
  411.             break;
  412.          case G_RESTART_PREVIOUS:
  413.             if (msg->Seconds < song_change_seconds + SMALL_DELAY ||
  414.                 (msg->Seconds == song_change_seconds + SMALL_DELAY && 
  415.                 msg->Micros <= song_change_micros) )
  416.                 {
  417.                 result[i++].type = UI_PREVIOUS_SONG;
  418.                 break;
  419.                 }
  420.             else
  421.                {
  422.                result[i++].type = UI_RESTART;
  423.                song_change_seconds = msg->Seconds;
  424.                song_change_micros = msg->Micros;
  425.                }
  426.             break;
  427.          case G_REWIND:
  428.             result[i].type = UI_JUMP_TO_PATTERN;
  429.             result[i].data.scalar = current_pattern;
  430.             if (msg->Seconds < pattern_change_seconds + SMALL_DELAY ||
  431.                 (msg->Seconds == pattern_change_seconds + SMALL_DELAY && 
  432.                 msg->Micros <= pattern_change_micros) )
  433.                 result[i].data.scalar--;
  434.                    /* give some immediate feedback to the user */
  435.             temp.scalar = result[i].data.scalar;
  436.             do_set_current(temp);
  437.                 i++;
  438.             break;
  439.          case G_FF:
  440.             result[i].type = UI_JUMP_TO_PATTERN;
  441.             result[i].data.scalar = current_pattern + 1;
  442.                   /* give some immediate feedback to the user */
  443.             temp.scalar = result[i].data.scalar;
  444.             do_set_current(temp);
  445.             i++;
  446.             break;
  447.          case G_SHOW:
  448.             set_pref_scalar(PREF_SHOW, TRUE);
  449.             break;
  450.          case G_PAUSE:
  451.             if (restart_msg)
  452.                {
  453.                send(restart_msg, TYPE_UNPAUSE);
  454.                restart_msg = 0;
  455.                }
  456.             else
  457.                {
  458.                struct ext_message *msg;
  459.                
  460.                msg = obtain_message();
  461.                restart_msg = obtain_message();
  462.                send(msg, TYPE_PAUSE);
  463.                }
  464.             }
  465.          GT_ReplyIMsg(msg);
  466.          break;
  467.       default:
  468.          GT_ReplyIMsg(msg);
  469.          }
  470.    }
  471.  
  472.  
  473. void requested_file(struct amiganame *name)
  474.    {
  475.    result[i].data.pointer = name;
  476.    result[i++].type = UI_LOAD_SONG;
  477.    }
  478.  
  479.    
  480. struct tag *get_ui()
  481.    {
  482.  
  483.    INIT_ONCE
  484.  
  485.    if (checkbrk())
  486.       result[i++].type = UI_QUIT;
  487.    
  488.    result[i].type = TAG_END;
  489.    
  490.    i = 0;
  491.    return result;
  492.    }
  493.  
  494.  
  495. void song_title(char *s)
  496.    {
  497.    static char title[25];
  498.  
  499.    INIT_ONCE;
  500.  
  501.    strncpy(title, s, 25);
  502.    if (ui_win)
  503.       GT_SetGadgetAttrs(title_gad, ui_win, 0, GTTX_Text, title, TAG_END);
  504.    /* stamp the time we changed the song */
  505.    CurrentTime(&song_change_seconds, &song_change_micros);
  506.    }
  507.  
  508. void status(char *s)   
  509.    {
  510.    INIT_ONCE;
  511.    
  512.    SetWindowTitles(ui_win, s ? s : WINDOW_TITLE, -1);
  513.    }
  514.  
  515. /* hook to change current pattern */
  516. LOCAL void do_set_current(VALUE p)
  517.    {
  518.    if (!inhibit_output)
  519.       {
  520.       INIT_ONCE;
  521.       if (ui_win)
  522.          GT_SetGadgetAttrs(pattern_gad, ui_win, 0, GTNM_Number, p.scalar, TAG_END);
  523.       }
  524.    current_pattern = p.scalar;
  525.    /* stamp the time we changed the pattern */
  526.    CurrentTime(&pattern_change_seconds, &pattern_change_micros);
  527.    }
  528.  
  529. /* hook to change current pattern total */
  530. LOCAL void do_set_total(VALUE p)
  531.     {
  532.     INIT_ONCE;
  533.    if (ui_win)
  534.       GT_SetGadgetAttrs(total_gad, ui_win, 0, GTNM_Number, p.scalar, TAG_END);
  535.     }
  536.  
  537. void display_pattern(int current, int total, int real)
  538.    {
  539.    struct ext_message *msg;
  540.  
  541.    INIT_ONCE 
  542.  
  543.    msg = obtain_message();
  544.     msg->data.hook.func = do_set_total;
  545.    msg->data.hook.p.scalar = total;
  546.    send(msg, TYPE_SYNC_DO);
  547.  
  548.    msg = obtain_message();
  549.     msg->data.hook.func = do_set_current;
  550.    msg->data.hook.p.scalar = current;
  551.    send(msg, TYPE_SYNC_DO);
  552.    }
  553.  
  554.  
  555.  
  556.  
  557. /***
  558.  ***
  559.  ***    notice() pseudo-system call.
  560.  ***    mostly used to report errors
  561.  ***
  562.  ***    The only difficulty comes from the fact
  563.  ***    that we may be called under any kind of environment
  564.  ***
  565.  ***/
  566.  
  567. #ifdef USE_ARQ
  568. #include "arq.h"
  569. /* arq 1.78 doesn't notice BuildEasyRequest().
  570.    I need to contact Martin Laubach about it
  571.        FidoNet: 2:310/3.14 
  572.        Usenet:  mjl@alison.at (home) 
  573.                                mjl@auto.tuwien.ac.at (work) 
  574.                 {cbmvax!cbmehq,mcsun!tuvie}!cbmvie!alison!mjl 
  575.  
  576.        Peter, the graphics and animation wizard, can be reached
  577.      2:310/42 in FidoNet.  
  578.  */
  579.  
  580. LOCAL struct ExtEasyStruct es =
  581.    {
  582.    0,
  583.    0,
  584.    ARQ_ID_INFO,
  585.    0,
  586.    ARQ_MAGIC,
  587.    0, 0, 0,
  588.    sizeof(struct EasyStruct),
  589.    0,
  590.    "Notice\xa0",
  591.    NULL,
  592.    "Proceed"
  593.    };
  594. LOCAL struct EasyStruct *esp = & (es.Easy);
  595. #else
  596. LOCAL struct EasyStruct es = 
  597.    {
  598.    sizeof(struct EasyStruct),
  599.    0,
  600.    "Notice",
  601.    NULL,
  602.    "Proceed"
  603.    };
  604. LOCAL struct EasyStruct *esp = &es;
  605. #endif
  606.  
  607.  
  608. void handle_notice(struct Window *w)
  609.    {
  610.    if (SysReqHandler(w, 0, FALSE) != -2)
  611.       {
  612.       remove_signal_handler(w->UserPort->mp_SigBit);
  613.       FreeSysRequest(w);
  614.       notice_win = 0;
  615.       }
  616.    }
  617.  
  618. void notice(char *s)
  619.    {
  620.    INIT_ONCE;
  621.    
  622.    if (!IntuitionBase)
  623.       {
  624.       fprintf(stderr, s);
  625.       fputc('\n', stderr);
  626.       }
  627.    else
  628.       {
  629.          /* wait for previous notice to go away */
  630.       while (notice_win)
  631.          await_events();
  632.       
  633.       esp->es_TextFormat = s;
  634.       notice_win = BuildEasyRequest(0, esp, NULL, NULL);
  635.       install_signal_handler(notice_win->UserPort->mp_SigBit, handle_notice, notice_win);
  636.       }
  637.    }
  638.  
  639.